<?php
defined('JETEE_PATH') or exit();

/**
 * Think 基础函数库
 * @category   Think
 * @package  Common
 * @author   liu21st <liu21st@gmail.com>
 */

/**
 * 获取模版文件 格式 项目://分组@主题/模块/操作
 * @param string $name 模版资源地址
 * @param string $layer 视图层（目录）名称
 * @return string
 */
function T($template='',$layer=''){
		if(is_file($template)) {
			return $template;
		}
		// 解析模版资源地址
		if(false === strpos($template,'://')){
			$template   =   APP_NAME.'://'.str_replace(':', '/',$template);
		}        
		$info   =   parse_url($template);
		$file   =   $info['host'].(isset($info['path'])?$info['path']:'');
		$group  =   isset($info['user'])?$info['user'].'/':(defined('GROUP_NAME')?GROUP_NAME.'/':'');
		$app    =   $info['scheme'];
		$layer  =   $layer?$layer:C('DEFAULT_V_LAYER');

		// 获取当前主题的模版路径
		if(($list = C('EXTEND_GROUP_LIST')) && isset($list[$app])){ // 扩展分组
			$baseUrl    =   $list[$app].'/'.$group.$layer.'/';
		}else{ 
			$baseUrl    =   TMPL_PATH.$group;
		}

		// 分析模板文件规则
		if('' == $file) {
			// 如果模板文件名为空 按照默认规则定位
			$file = MODULE_NAME . C('TMPL_FILE_DEPR') . ACTION_NAME;
		}elseif(false === strpos($file, '/')){
			$file = MODULE_NAME . C('TMPL_FILE_DEPR') . $file;
		}
		return $baseUrl.$file.C('TMPL_TEMPLATE_SUFFIX');
}

/**
 * 获取输入参数 支持过滤和默认值
 * 使用方法:
 * <code>
 * I('id',0); 获取id参数 自动判断get或者post
 * I('post.name','','htmlspecialchars'); 获取$_POST['name']
 * I('get.'); 获取$_GET
 * </code> 
 * @param string $name 变量的名称 支持指定类型
 * @param mixed $default 不存在的时候默认值
 * @param mixed $filter 参数过滤方法
 * @return mixed
 */
function I($name,$default='',$filter=null,$is_array=false) {
	if(strpos($name,'.')) { // 指定参数来源
		list($method,$name) =   explode('.',$name,2);
	}else{ // 默认为自动判断
		$method = 'param';
	}
	switch(strtolower($method)) {
		case 'get'     :   $input =& $_GET;break;
		case 'post'    :   $input =& $_POST;break;
		case 'put'     :   parse_str(file_get_contents('php://input'), $input);break;
		case 'param'   :  
			switch($_SERVER['REQUEST_METHOD']) {
				case 'POST':
					$input  =  $_POST;
					break;
				case 'PUT':
					parse_str(file_get_contents('php://input'), $input);
					break;
				default:
					$input  =  $_GET;
			}
			break;
		case 'request' :   $input =& $_REQUEST;   break;
		case 'session' :   $input =& $_SESSION;   break;
		case 'cookie'  :   $input =& $_COOKIE;    break;
		case 'server'  :   $input =& $_SERVER;    break;
		case 'globals' :   $input =& $GLOBALS;    break;
		default:
			return NULL;
	}
	if(empty($name)) { // 获取全部变量
		$data       =   $input; 
		$filters    =   isset($filter)?$filter:C('DEFAULT_FILTER');
		if($filters) {
			$filters    =   explode(',',$filters);
			foreach($filters as $filter){
				$data   =   array_map($filter,$data); // 参数过滤
			}
		}        
	}elseif(isset($input[$name])) { // 取值操作
		$data       =	$input[$name];
		$filters    =   isset($filter)?$filter:C('DEFAULT_FILTER');
		if($filters) {
			$filters    =   explode(',',$filters);
			foreach($filters as $filter){
				if(function_exists($filter)) {
					$data   =   $is_array && is_array($data) ? array_map($filter,$data): $filter($data); // 参数过滤
				}else{
					$data   =   filter_var($data,is_int($filter)?$filter:filter_id($filter));
					if(false === $data) {
						return	 isset($default)?$default:NULL;
					}
				}
			}
		}
	}else{ // 变量默认值
		$data       =	 isset($default)?$default:NULL;
	}
	is_array($data) && array_walk_recursive($data,'think_filter');
	return $data;
}

/**
 * 记录和统计时间（微秒）和内存使用情况
 * 使用方法:
 * <code>
 * G('begin',floatval)  // 记录标记位
 * echo G('begin','end',8)  //end可以不定义 精确到小数后8位
 * G('begin'); // 记录开始标记位
 * // ... 区间运行代码
 * G('end'); // 记录结束标签位
 * echo G('begin','end',6); // 统计区间运行时间 精确到小数后6位
 * echo G('begin','end','m'); // 统计区间内存使用情况
 * 如果end标记位没有定义，则会自动以当前作为标记位
 * 其中统计内存使用需要 MEMORY_LIMIT_ON 常量为true才有效
 * </code>
 * @param string $start 开始标签
 * @param string $end 结束标签
 * @param integer|string $dec 小数位或者m 
 * @return mixed
 */
function G($start,$end='',$dec=4) {
	static $_info       =   array();
	static $_mem        =   array();
	if(is_float($end)) { // 记录时间
		$_info[$start]  =   $end;
	}elseif(!empty($end)){ // 统计时间和内存使用
		if(!isset($_info[$end])) $_info[$end]       =  microtime(TRUE);
		if(MEMORY_LIMIT_ON && $dec=='m'){
			if(!isset($_mem[$end])) $_mem[$end]     =  memory_get_usage();
			return number_format(($_mem[$end]-$_mem[$start])/1024);          
		}else{
			return number_format(($_info[$end]-$_info[$start]),$dec);
		}       
			
	}else{ // 记录时间和内存使用
		$_info[$start]  =  microtime(TRUE);
		if(MEMORY_LIMIT_ON) $_mem[$start]           =  memory_get_usage();
	}
}

/**
 * 设置和获取统计数据
 * 使用方法:
 * <code>
 * N('db',1); // 记录数据库操作次数
 * N('read',1); // 记录读取次数
 * echo N('db'); // 获取当前页面数据库的所有操作次数
 * echo N('read'); // 获取当前页面读取次数
 * </code> 
 * @param string $key 标识位置
 * @param integer $step 步进值
 * @return mixed
 */
function N($key, $step=0,$save=false) {
	static $_num    = array();
	if (!isset($_num[$key])) {
		$_num[$key] = (false !== $save)? S('N_'.$key) :  0;
	}
	if (empty($step))
		return $_num[$key];
	else
		$_num[$key] = $_num[$key] + (int) $step;
	if(false !== $save){ // 保存结果
		S('N_'.$key,$_num[$key],$save);
	}
}

/**
 * 字符串命名风格转换
 * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
 * @param string $name 字符串
 * @param integer $type 转换类型
 * @return string
 */
function parse_name($name, $type=0) {
	if ($type) {
		return ucfirst(preg_replace_callback('/_([a-zA-Z])/',  function($m){return strtoupper($m[1]);}, $name));
	} else {
		return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
	}
}

/**
 * 优化的require_once  不重复加载
 * @param string $filename 文件地址
 * @return boolean
 */
function require_cache($filename) {
	static $_importFiles = array();
	if (!isset($_importFiles[$filename])) {
		if (file_exists_case($filename)) {
			require $filename;
			$_importFiles[$filename] = true;
		} else {
			$_importFiles[$filename] = false;
		}
	}
	return $_importFiles[$filename];
}

/**
 * 批量导入文件 成功则返回
 * @param array $array 文件数组
 * @param boolean $return 加载成功后是否返回
 * @return boolean
 */
function require_array($array,$return=false){
	foreach ($array as $file){
		if (require_cache($file) && $return) return true;
	}
	if($return) return false;
}

/**
 * 区分大小写的文件存在判断
 * @param string $filename 文件地址
 * @return boolean
 */
function file_exists_case($filename) {
	if (is_file($filename)) {
		if (IS_WIN && C('APP_FILE_CASE')) {
			if (basename(realpath($filename)) != basename($filename))
				return false;
		}
		return true;
	}
	return false;
}


/**
 * 基于命名空间方式导入函数库   默认调用EXTEND_PATH/Function/下  
 * load('@.function')
 * @param string $name 函数库命名空间字符串 			@.function 表示调用项目公共目录Common/function.php
 * @param string $baseUrl 起始路径
 * @param string $ext 导入的文件扩展名
 * @return void
 */
function load($name, $baseUrl='', $ext='.php') {
	$name = str_replace(array('.', '#'), array('/', '.'), $name);
	if (empty($baseUrl)) {
		if (0 === strpos($name, '@/')) {
			//加载当前项目函数库
			$baseUrl    = COMMON_PATH;
			$name       = substr($name, 2);
		} else {
			//加载JETEE 系统函数库
			$baseUrl    = EXTEND_PATH . 'Function/';
		}
	}
	if (substr($baseUrl, -1) != '/')
		$baseUrl       .= '/';
	require_cache($baseUrl . $name . $ext);
}

/**
 * 快速导入第三方框架类库 所有第三方框架的类库文件统一放到 系统的Vendor目录下面
 * @param string $class 类库
 * @param string $baseUrl 基础目录
 * @param string $ext 类库后缀 
 * @return boolean
 */
function vendor($class, $baseUrl = '', $ext='.class.php') {
	if (empty($baseUrl))
		$baseUrl = VENDOR_PATH;
	return require_cache($baseUrl.$class.$ext);
}


/**
 * A函数用于实例化Action 格式：[项目://][分组/]模块   @/group/module
 * @param string $name Action资源地址
 * @param string $layer 控制层名称
 * @param boolean $common 是否公共目录
 * @return Action|false
 */
function A($name,$layer='',$common=false) {
	static $_action = array();
	$layer      =   $layer?$layer:C('DEFAULT_C_LAYER');//Action
	if(strpos($name,'://')) {// 指定项目
		$name   =  dirname(APP_PATH).'/'.str_replace('://','/Lib/'.$layer.'/',$name);
	}else{
		$name   =  '@/'.$layer.'/'.$name;
	}
	if(isset($_action[$name]))  return $_action[$name];
	$path           =   explode('/',$name);
	if($common) { // 加载公共类库目录
		require_cache(LIB_PATH . str_replace('@/','',$name).$layer.EXT);
	}else{
		require_cache(str_replace('@/',LIB_PATH,$name).$layer.EXT);
	}
	$class      =   basename($name.$layer);
	if(class_exists($class,false)) {
		$action             =   new $class();
		$_action[$name]     =   $action;
		return $action;
	}else {
		return false;
	}
}

/**
 * 远程调用模块的操作方法 URL 参数格式 [项目://][分组/]模块/操作
 * @param string $url 调用地址
 * @param string|array $vars 调用参数 支持字符串和数组 
 * @param string $layer 要调用的控制层名称
 * @return mixed
 */
function R($url,$vars=array(),$layer='') {
	$info   =   pathinfo($url);
	$action =   $info['basename'];
	$module =   $info['dirname'];
	$class  =   A($module,$layer);
	if($class){
		if(is_string($vars)) {
			parse_str($vars,$vars);
		}
		return call_user_func_array(array(&$class,$action.C('ACTION_SUFFIX')),$vars);
	}else{
		return false;
	}
}

/**
 * 获取和设置语言定义(区分大小写)
 * @param string|array $name 语言变量
 * @param string $value 语言值
 * @return mixed
 */
function L($name=null, $value=null) {
	static $_lang = array();
	// 空参数返回所有定义
	if (empty($name))
		return $_lang;
	// 判断语言获取(或设置)
	// 若不存在,直接返回
	if (is_string($name)) {
		if (!strpos($name, '.')) {
			if (is_null($value))
				return isset($_lang[$name]) ? $_lang[$name] : $name;
			$_lang[$name] = $value;
			return;
		}
		// 二维数组设置和获取支持
		$name = explode('.', $name);
		if (is_null($value))
			return isset($_lang[$name[0]][$name[1]]) ? $_lang[$name[0]][$name[1]] : $name[1];
		$_lang[$name[0]][$name[1]] = $value;
		return;
	}
	// 批量定义
	if (is_array($name))
		$_lang = array_merge($_lang, $name);
	return null; // 避免非法参数
}

/**
 * 获取和设置配置参数 支持批量定义
 * @param string|array $name 配置变量   字条 一级数组 不区分大小写
 * @param mixed $value 配置值
 * @return mixed
 */
function C($name=null, $value=null) {
	static $_config = array();
	// 无参数时获取所有
	if (empty($name)) {
		if(!empty($value) && $array = json_decode(S('c_'.$value,true),true)) {
			$_config = array_merge($_config, array_change_key_case($array));
		}
		return $_config;
	}
	// 优先执行设置获取或赋值
	if (is_string($name)) {
		if (!strpos($name, '.')) {
			$name = strtolower($name);
			if (is_null($value))
				return isset($_config[$name]) ? $_config[$name] : null;
			$_config[$name] = $value;
			return;
		}
		// 二维数组设置和获取支持
		$name = explode('.', $name);
		$name[0]   =  strtolower($name[0]);
		if (is_null($value))
			return isset($_config[$name[0]][$name[1]]) ? $_config[$name[0]][$name[1]] : null;
		$_config[$name[0]][$name[1]] = $value;
		return;
	}
	// 批量设置
	if (is_array($name)){
		$_config = array_merge($_config, array_change_key_case($name));
		if(!empty($value)) {// 保存配置值
			S('c_'.$value,json_encode($_config));
		}
	   return;
	}
	return null; // 避免非法参数
}

/**
 * 处理标签扩展
 * @param string $tag 标签名称
 * @param mixed $params 传入参数
 * @return mixed
 */
function tag($tag, &$params=NULL) {
	// 系统标签扩展
	$tags    = C('tags.' . $tag);
	if($tags) {
		if(APP_DEBUG) {
			G($tag.'Start');
			trace('[ '.$tag.' ] --START--','','INFO');
		}
		// 执行扩展
		foreach ($tags as $key=>$name) {
			if(!is_int($key)) { // 指定行为类的完整路径 用于模式扩展
				$name   = $key;
			}
			B($name, $params);
		}
		if(APP_DEBUG) { // 记录行为的执行日志
			trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO');
		}
	}else{ // 未执行任何行为 返回false
		return false;
	}
}

/**
 * 动态添加行为扩展到某个标签
 * @param string $tag 标签名称
 * @param string $behavior 行为名称
 * @param string $path 行为路径 
 * @return void
 */
function add_tag_behavior($tag,$behavior,$path='') {
	$array      =  C('tags.'.$tag);
	if(!$array) {
		$array  =  array();
	}
	if($path) {
		$array[$behavior] = $path;
	}else{
		$array[] =  $behavior;
	}
	C('tags.'.$tag,$array);
}

/**
 * 执行某个行为
 * @param string $name 行为名称
 * @param Mixed $params 传入的参数
 * @return void
 */
function B($name, &$params=NULL) {
	if(strpos($name,'/')){
		list($name,$method) = explode('/',$name);
	}else{
		$method     =   'run';
	}
	$class      = $name.'Behavior';
	if(APP_DEBUG) {
		G('behaviorStart');
	}
	$behavior   = new $class();
	$behavior->$method($params);
	if(APP_DEBUG) { // 记录行为的执行日志
		G('behaviorEnd');
		trace($name.' Behavior ::'.$method.' [ RunTime:'.G('behaviorStart','behaviorEnd',6).'s ]','','INFO');
	}
}

/**
 * 去除代码中的空白和注释
 * @param string $content 代码内容
 * @return string
 */
function strip_whitespace($content) {
	$stripStr   = '';
	//分析php源码
	$tokens     = token_get_all($content);
	$last_space = false;
	for ($i = 0, $j = count($tokens); $i < $j; $i++) {
		if (is_string($tokens[$i])) {
			$last_space = false;
			$stripStr  .= $tokens[$i];
		} else {
			switch ($tokens[$i][0]) {
				//过滤各种PHP注释
				case T_COMMENT:
				case T_DOC_COMMENT:
					break;
				//过滤空格
				case T_WHITESPACE:
					if (!$last_space) {
						$stripStr  .= ' ';
						$last_space = true;
					}
					break;
				case T_START_HEREDOC:
					$stripStr .= "<<<THINK\n";
					break;
				case T_END_HEREDOC:
					$stripStr .= "THINK;\n";
					for($k = $i+1; $k < $j; $k++) {
						if(is_string($tokens[$k]) && $tokens[$k] == ';') {
							$i = $k;
							break;
						} else if($tokens[$k][0] == T_CLOSE_TAG) {
							break;
						}
					}
					break;
				default:
					$last_space = false;
					$stripStr  .= $tokens[$i][1];
			}
		}
	}
	return $stripStr;
}
/**
 * 添加和获取页面Trace记录
 * @param string $value 变量
 * @param string $label 标签
 * @param string $level 日志级别 
 * @param boolean $record 是否记录日志
 * @return void
 */
function trace($value='[think]',$label='',$level='DEBUG',$record=false) {
	static $_trace =  array();
	if('[think]' === $value){ // 获取trace信息
		return $_trace;
	}else{
		$info   =   ($label?$label.':':'').print_r($value,true);
		if('ERR' == $level && C('TRACE_EXCEPTION')) {// 抛出异常
			throw_exception($info);
		}
		$level  =   strtoupper($level);
		if(!isset($_trace[$level])) {
				$_trace[$level] =   array();
			}
		$_trace[$level][]   = $info;
		if((defined('IS_AJAX') && IS_AJAX) || C('LOG_RECORD')  || $record) {
			Log::record($info,$level,$record);
		}
	}
}

//[RUNTIME]
// 编译文件
function compile($filename) {
	$content        = file_get_contents($filename);
	// 替换预编译指令
	$content        = preg_replace('/\/\/\[RUNTIME\](.*?)\/\/\[\/RUNTIME\]/s', '', $content);
	$content        = substr(trim($content), 5);
	if ('?>' == substr($content, -2))
		$content    = substr($content, 0, -2);
	return $content;
}

// 根据数组生成常量定义
function array_define($array,$check=true) {
	$content = "\n";
	foreach ($array as $key => $val) {
		$key = strtoupper($key);
		if($check)   $content .= 'defined(\'' . $key . '\') or ';
		if (is_int($val) || is_float($val)) {
			$content .= "define('" . $key . "'," . $val . ');';
		} elseif (is_bool($val)) {
			$val = ($val) ? 'true' : 'false';
			$content .= "define('" . $key . "'," . $val . ');';
		} elseif (is_string($val)) {
			$content .= "define('" . $key . "','" . addslashes($val) . "');";
		}
		$content    .= "\n";
	}
	return $content;
}



/**
 * 取得当前的域名 完整 协议 +域名/ip+端口 https://www.jetee.cn:8080
 *
 * @access  public
 *
 * @return  string      当前的域名
 */
function get_domain()
{
	static $get_domain=null;
	if($get_domain!==null)	{
		return $get_domain;
	}
	/* 协议 */
	$protocol = IS_SSL?'https://':'http://';

	/* 域名或IP地址 */
	if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])){
		$host = $_SERVER['HTTP_X_FORWARDED_HOST'];
	}elseif (isset($_SERVER['HTTP_HOST'])){
		$host = $_SERVER['HTTP_HOST'];
	}else{
		/* 端口 */
		if (isset($_SERVER['SERVER_PORT']))	{
			$port = ':' . $_SERVER['SERVER_PORT'];
			if ((':80' == $port && 'http://' == $protocol) || (':443' == $port && 'https://' == $protocol)){
				$port = '';
			}
		}else{
			$port = '';
		}
		
		if (isset($_SERVER['SERVER_NAME']))	{
			$host = $_SERVER['SERVER_NAME'] . $port;
		}elseif (isset($_SERVER['SERVER_ADDR'])){
			$host = $_SERVER['SERVER_ADDR'] . $port;
		}
	}
	return $get_domain=$protocol . $host;
}
/**
 * 判断是否SSL协议
 * @return boolean
 */
function is_ssl() {
	if(isset($_SERVER['HTTPS']) && ('1' == $_SERVER['HTTPS'] || 'on' == strtolower($_SERVER['HTTPS']))){
		return true;
	}elseif(isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'] )) {
		return true;
	}
	return false;
}

/**
 * 取得设置cookie共享的域名   如.music.qq.com   .ma863.com  去除当前子域名
 *
 * @access  public
 *
 * @return  string      如.ma863.net
 */
function get_cookie_domain()
{
	static $get_domain=null;
	if($get_domain!==null)	{
		return $get_domain;
	}
	/* 域名或IP地址 */
	if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])){
		$get_domain = $_SERVER['HTTP_X_FORWARDED_HOST'];
	}elseif (isset($_SERVER['HTTP_HOST'])){
		$get_domain = $_SERVER['HTTP_HOST'];
	}elseif(isset($_SERVER['SERVER_NAME']))	{
		$get_domain = $_SERVER['SERVER_NAME'];		
	}
	
	//去除 zc.ma863.net中zc
	if(empty($get_domain)){
		$get_domain = $_SERVER['SERVER_ADDR'];
	}
	elseif(substr_count($get_domain,'.')!=3){//如果不是ip 255.255.255.255
		$get_domain=explode('.',$get_domain);
		if(count($get_domain)>2)array_shift($get_domain);
		$get_domain='.'.implode('.',$get_domain);
	}
	return $get_domain;
}
//[/RUNTIME]

/**
 * E函数用于实例化一个有用模型文件的Model(connection)     如E('Store')->lists();
 * @param string $name Model名称 支持指定基础模型 例如 MongoModel:User
 * @param string $tablePrefix 表前缀
 * @return Model
 */
function E($table,$layer=''){
	static $_model  = array();
	if (!isset($_model[$table])){
		$layer=$layer?$layer:C('DEFAULT_M_LAYER');
		$t=$table.$layer;
		$_model[$table] = new $t();
	}
	return $_model[$table];
}
/**
 * db函数用于实例化connection
 * @param string $table  默认空不设置表名 		db('user u')
 * @param string $prefix 表前缀  NULL为没有前缀 ''为加C('DB_PREFIX')
 * @return $connection 数据库连接信息
 */
function db($table='',$prefix=''){
    static $db=null;
	if(!$db){
		require_once CORE_PATH.'Core/PdoMysql.class.php';
		$db = new Core\PdoMysql(C('DB_HOST'), C('DB_USER'), C('DB_PWD'), C('DB_NAME'));
	}
	if($table!==''){
		if($prefix!==NULL){
			$table=$prefix==='' ? C('DB_PREFIX').$table : $prefix.$table;
		}
		$db->setTable($table);
		$db->fromRaw($db->getTable());
	}
	return $db;
}

function p($a,$t=false){
	return print_r($a,$t);
}


